use clap::Parser;
use std::fs;
use std::path::Path;
use walkdir::{DirEntry, WalkDir};

/// 文件扁平化工具：将多级目录下的文件复制到单一目录，并使用原路径作为新文件名
#[derive(Parser, Debug)]
#[clap(author, version, about)]
struct Args {
    /// 源目录路径
    #[clap(short, long)]
    source: String,

    /// 目标目录路径
    #[clap(short, long)]
    destination: String,

    /// 分隔符，用于将原路径转换为文件名
    #[clap(short = 'p', long, default_value = ".")]
    separator: String,
    
    /// 要忽略的文件夹或文件名，可指定多个，例如: -i .idea data
    #[clap(short = 'i', long = "ignore", num_args = 1..)]
    ignore: Vec<String>,
}

/// 检查是否应该忽略这个路径
fn should_ignore(entry: &DirEntry, ignore_list: &[String], dest_dir: &Path) -> bool {
    // 如果忽略列表为空且目标目录不在源目录内，则不忽略任何文件
    if ignore_list.is_empty() && !is_subdirectory(entry.path(), dest_dir) {
        return false;
    }
    
    let path = entry.path();
    
    // 检查是否是目标目录或其子目录
    if is_subdirectory(path, dest_dir) {
        return true;
    }
    
    let file_name = path.file_name().unwrap_or_default().to_string_lossy().to_lowercase();
    
    // 检查文件名是否在忽略列表中（部分匹配）
    if ignore_list.iter().any(|ignored| {
        let ignored = ignored.to_lowercase();
        file_name.contains(&ignored)
    }) {
        return true;
    }
    
    // 检查路径的任何部分是否在忽略列表中（部分匹配）
    for ancestor in path.ancestors() {
        if let Some(name) = ancestor.file_name() {
            let name_str = name.to_string_lossy().to_lowercase();
            if ignore_list.iter().any(|ignored| {
                let ignored = ignored.to_lowercase();
                name_str.contains(&ignored)
            }) {
                return true;
            }
        }
    }
    
    false
}

/// 检查path是否是parent_dir的子目录
fn is_subdirectory(path: &Path, parent_dir: &Path) -> bool {
    if let Ok(relative) = path.strip_prefix(parent_dir) {
        !relative.as_os_str().is_empty()
    } else {
        false
    }
}

fn main() {
    let args = Args::parse();

    let source_dir = Path::new(&args.source);
    let dest_dir = Path::new(&args.destination);

    // 确保源目录存在
    if !source_dir.exists() {
        panic!("源目录不存在: {}", args.source);
    }

    // 确保目标目录存在，如果不存在则创建
    if !dest_dir.exists() {
        fs::create_dir_all(dest_dir).unwrap();
    }
    
    // 检查目标目录是否是源目录的子目录
    let dest_is_subdirectory = is_subdirectory(dest_dir, source_dir);
    if dest_is_subdirectory {
        println!("警告: 目标目录是源目录的子目录，已自动将其添加到忽略列表中");
    }
    
    // 输出忽略的文件夹或文件名
    if !args.ignore.is_empty() {
        println!("将忽略以下文件夹或文件: {:?}", args.ignore);
    }

    // 遍历源目录中的所有文件
    for entry in WalkDir::new(source_dir).into_iter().filter_entry(|e| !should_ignore(e, &args.ignore, dest_dir)) {
        let entry = entry.unwrap();
        let path = entry.path();

        // 跳过目录
        if path.is_dir() {
            continue;
        }

        // 获取相对路径
        let relative_path = path.strip_prefix(source_dir).unwrap();

        // 创建新的文件名: 使用路径分隔符替换为指定分隔符
        let new_filename = relative_path
            .components()
            .map(|c| c.as_os_str().to_string_lossy().into_owned())
            .collect::<Vec<_>>()
            .join(&args.separator);

        // 构建目标文件路径（添加.md扩展名）
        let dest_path = dest_dir.join(format!("{}.md", new_filename));

        // 创建目标文件的父目录（如果需要）
        if let Some(parent) = dest_path.parent() {
            if !parent.exists() {
                fs::create_dir_all(parent).unwrap();
            }
        }

        // 复制文件
        fs::copy(path, &dest_path).unwrap();

        println!("已复制: {} -> {}", path.display(), dest_path.display());
    }
    println!("完成! 所有文件已扁平化复制到: {}", args.destination);
}
